use regex::Regex;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
use std::collections::{HashMap, HashSet};
use std::path::Path;

fn parse_json_file() -> io::Result<String> {
    // 解析读入文件
    let project_root = env!("CARGO_MANIFEST_DIR");
    let file_path = Path::new(&project_root).join("district.json");
    let test_file = File::open(file_path)?;
    let reader = BufReader::new(test_file);
    let json_str = reader.lines().collect::<Result<String, _>>()?;
    Ok(json_str)
}

fn find_top_city(top_city: &mut Vec<usize>, city_index: usize) -> usize {
    // 并查集
    if city_index == top_city[city_index] {
        city_index
    } else {
        top_city[city_index] = find_top_city(top_city, top_city[city_index]);
        top_city[city_index]
    }
}

pub fn count_provinces() -> String {
    let json_str = parse_json_file().unwrap();
    let mut ans: String = String::new();
    let re_test_point = Regex::new(r#""(\d+)":\s*\{([^}]*)\}"#).unwrap();
    let re_key_value = Regex::new(r#""([^"]+)":\s*\[([^\]]*)\]"#).unwrap();
    for test_point in re_test_point.captures_iter(&json_str) {
        let mut city_index: HashMap<String, usize> = HashMap::new(); // 对城市名称建立索引
        let mut city_count = 0;
        let mut top_city : Vec<usize> = Vec::new(); // 并查集
        let mut get_index = |city_name: &str| {
            if city_index.contains_key(city_name) {
                *city_index.get(city_name).unwrap()
            } else {
                city_index.insert(city_name.to_string(), city_count);
                city_count += 1;
                city_count - 1
            }
        };
        for key_value in re_key_value.captures_iter(&test_point[2]) {
            let key_index = get_index(&key_value[1]);
            if key_index >= top_city.len() { 
                top_city.resize(key_index + 1, key_index);
            }
            let values_index: Vec<usize> = key_value[2].split(',').map(|v| get_index(v.trim().trim_matches('"'))).collect();
            let top_of_key = find_top_city(&mut top_city, key_index);
            for value_index in values_index {
                if value_index >= top_city.len() { 
                    top_city.resize(value_index + 1, value_index);
                }
                let top_of_value = find_top_city(&mut top_city, value_index);
                if top_of_key != top_of_value {
                    top_city[top_of_value] = top_of_key;
                }
            }
        }
        let mut city_group: HashSet<usize> = HashSet::new();
        for i in 0..city_count {
            city_group.insert(find_top_city(&mut top_city, i));
        }
        let append_str = if ans.len() > 0 { format!(",{}", city_group.len()) } else { format!("{}", city_group.len()) };
        ans.push_str(&append_str);
    }   
    ans
}
